package com.econ.powercloud.ems.service.biz;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.econ.powercloud.common.base.facade.enums.StatusType;
import com.econ.powercloud.common.base.facade.exception.CommonRuntimeException;
import com.econ.powercloud.common.base.facade.pojo.PageResult;
import com.econ.powercloud.common.base.facade.util.JacksonUtil;
import com.econ.powercloud.ems.common.enums.*;
import com.econ.powercloud.ems.constant.SysConstant;
import com.econ.powercloud.ems.dal.entity.EmsArea;
import com.econ.powercloud.ems.dal.entity.EmsPriceModel;
import com.econ.powercloud.ems.dal.entity.EmsPriceModelDetail;
import com.econ.powercloud.ems.pojo.EmsAreaVO;
import com.econ.powercloud.ems.pojo.EmsPriceModelDetailVO;
import com.econ.powercloud.ems.pojo.EmsPriceModelVO;
import com.econ.powercloud.ems.pojo.requestVO.EmsPriceModelDetailEditVO;
import com.econ.powercloud.ems.pojo.requestVO.EmsPriceModelDetailRequestVO;
import com.econ.powercloud.ems.service.dao.EmsAreaDAO;
import com.econ.powercloud.ems.service.dao.EmsPriceModelDAO;
import com.econ.powercloud.ems.service.dao.EmsPriceModelDetailDAO;
import com.econ.powercloud.ems.util.TimeUtil;
import com.google.common.collect.Lists;
import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.RequestParam;

import javax.validation.constraints.NotNull;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

import static java.util.stream.Collectors.toList;

@Service
public class EPModelService {

    @Autowired
    private EmsPriceModelDAO emsPriceModelDAO;
    @Autowired
    private EmsAreaDAO emsAreaDAO;
    @Autowired
    private EmsPriceModelDetailDAO emsPriceModelDetailDAO;

    /**
     * 新增电价模型信息
     * @param emsPriceModelVO
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public void addModelInfo(EmsPriceModelVO emsPriceModelVO) {
        Assert.notNull(emsPriceModelVO,"参数错误!");
        //新增电价模型校验省份、城市、名称是否重复
        List<EmsPriceModel> modelList = emsPriceModelDAO.list();
        List<String> modelNameList = modelList.stream().map(EmsPriceModel::getModelName).collect(toList());
        Assert.isTrue(!modelNameList.contains(emsPriceModelVO.getModelName()),"电价模型名称重复!");
        List<EmsPriceModel> provinceList = modelList.stream().filter(d-> Objects.equals(emsPriceModelVO.getProvince(),d.getProvince())).collect(toList());
        if(!CollectionUtils.isEmpty(provinceList)){
            provinceList.stream().forEach(d->{
                List<String> cityList = Arrays.asList(d.getCity().split(","));
                List<String> requestCityList = Arrays.asList(emsPriceModelVO.getCity().split(","));
                List<String> intersection = cityList.stream().filter(requestCityList::contains).collect(Collectors.toList());
                if(!CollectionUtils.isEmpty(intersection)){
                    throw new CommonRuntimeException(StatusType.FAIL,"该电价模型使用的部分城市已被使用!");
                }
            });
        }
        EmsPriceModel emsPriceModel = JacksonUtil.convertToObj(emsPriceModelVO, EmsPriceModel.class);
        emsPriceModel.setGmtCreate(System.currentTimeMillis());
        emsPriceModel.setGmtModify(System.currentTimeMillis());
        emsPriceModelDAO.save(emsPriceModel);
    }

    /**
     * 根据省份查询电价模型
     * @return
     * @param province
     */
    public PageResult<List<EmsPriceModelVO>> selectModelList(Integer province, Integer pageNo, Integer pageSize) {
        Page<EmsPriceModel> page = emsPriceModelDAO.selectPageByProvince(province,pageNo,pageSize);
        if(CollectionUtils.isEmpty(page.getRecords())){
            return PageResult.<List<EmsPriceModelVO>>builder().data(Collections.emptyList()).build();
        }
        List<EmsPriceModelVO> emsPriceModelVOS = JacksonUtil.convertToList(page.getRecords(),EmsPriceModelVO.class);
        //获取城市名称
        Map<Integer,EmsArea> areaMap = emsAreaDAO.list().stream().collect(Collectors.toMap(EmsArea::getCityCode,d->d,(p1,p2)->p1));
        emsPriceModelVOS.stream().forEach(d->{
            d.setProvinceName(areaMap.get(d.getProvince()).getCityName());
            d.setCityName(this.getCityName(d.getCity(),areaMap));
        });
        return PageResult.<List<EmsPriceModelVO>>builder().data(emsPriceModelVOS).pageNo(pageNo).totalCount((int)page.getTotal()).build();
    }

    /**
     * 查询单个电价模型
     */
    public EmsPriceModelVO selectModelById(Integer modelId) {
        EmsPriceModel model = emsPriceModelDAO.getById(modelId);
        Assert.notNull(model,"电价模型不存在！");
        EmsPriceModelVO emsPriceModelVO = JacksonUtil.convertToObj(model,EmsPriceModelVO.class);
        //获取城市名称
        Map<Integer,EmsArea> areaMap = emsAreaDAO.list().stream().collect(Collectors.toMap(EmsArea::getCityCode,d->d,(p1,p2)->p1));
        emsPriceModelVO.setProvinceName(areaMap.get(emsPriceModelVO.getProvince()).getCityName());
        emsPriceModelVO.setCityName(this.getCityName(emsPriceModelVO.getCity(),areaMap));
        return emsPriceModelVO;
    }

    /**
     * 查询电价模型的详情
     */
    public PageResult<List<EmsPriceModelDetailVO>> selectModelDetailList(Integer modelId, String applyTime, Integer priceType, Integer voltageLevel,
                                                                         Integer pageNo, Integer pageSize){
        Page<EmsPriceModelDetail> page = emsPriceModelDetailDAO.selectPageByCondition(modelId, applyTime, priceType, voltageLevel, pageNo, pageSize);
        if(CollectionUtils.isEmpty(page.getRecords())){
            return PageResult.<List<EmsPriceModelDetailVO>>builder().data(Collections.emptyList()).build();
        }
        List<EmsPriceModelDetailVO> detailVOList = JacksonUtil.convertToList(page.getRecords(),EmsPriceModelDetailVO.class);
        //补充数据
        this.initPriceModelOtherInfo(detailVOList);
        return PageResult.<List<EmsPriceModelDetailVO>>builder().data(detailVOList).pageNo(pageNo).totalCount((int)page.getTotal()).build();
    }

    /**
     * 查询单个电价模型信息
     */
    public EmsPriceModelDetailVO selectModelDetailInfo(Integer pid){
        EmsPriceModelDetail modelDetail = emsPriceModelDetailDAO.getById(pid);
        Assert.notNull(modelDetail,"未查询指定的电价模型详情信息!");
        EmsPriceModelDetailVO modelDetailVO = JacksonUtil.convertToObj(modelDetail,EmsPriceModelDetailVO.class);
        this.initPriceModelOtherInfo(Collections.singletonList(modelDetailVO));
        return modelDetailVO;
    }

    /**
     * 新增电价(电价模型详情)
     */
    @Transactional(rollbackFor = Exception.class)
    public void addModelDetail(EmsPriceModelDetailRequestVO requestVO){
        //校验新增电价是否重复
        if(this.judgePriceModelDetailRepeat(requestVO, null)){
            throw new CommonRuntimeException(StatusType.FAIL,"新增电价已存在!");
        }
        EmsPriceModelDetail modelDetail = JacksonUtil.convertToObj(requestVO,EmsPriceModelDetail.class);
        modelDetail.setGmtCreate(System.currentTimeMillis());
        modelDetail.setGmtModify(System.currentTimeMillis());
        emsPriceModelDetailDAO.save(modelDetail);
    }

    /**
     * 修改电价(电价模型详情)
     */
    @Transactional(rollbackFor = Exception.class)
    public void modifyModelDetail(EmsPriceModelDetailEditVO editVO){
        //校验当前电价是否可以修改
        EmsPriceModelDetail modelDetail = emsPriceModelDetailDAO.getById(editVO.getPid());
        Assert.notNull(modelDetail,"数据不存在!");
        if(!isAfterTheCurrentMonthTime(modelDetail.getApplyTime())){
            throw new CommonRuntimeException(StatusType.FAIL,"该电价已被使用无法修改!");
        }
        //校验新增电价是否重复
        if(this.judgePriceModelDetailRepeat(editVO, Lists.newArrayList(editVO.getPid()))){
            throw new CommonRuntimeException(StatusType.FAIL,"修改后电价已重复!");
        }
        EmsPriceModelDetail updateModelDetail = JacksonUtil.convertToObj(editVO,EmsPriceModelDetail.class);
        updateModelDetail.setGmtModify(System.currentTimeMillis());
        emsPriceModelDetailDAO.updateById(updateModelDetail);
    }

    @Transactional(rollbackFor = Exception.class)
    public void deleteModelDetail(Integer pid){
        //校验当前电价是否可以删除
        EmsPriceModelDetail modelDetail = emsPriceModelDetailDAO.getById(pid);
        if(!isAfterTheCurrentMonthTime(modelDetail.getApplyTime())){
            throw new CommonRuntimeException(StatusType.FAIL,"该电价已被使用无法删除!");
        }
        emsPriceModelDetailDAO.removeById(pid);
    }

    /**
     * 获取全国省份list
     * @return
     */
    public List<EmsAreaVO> getProvinceList() {
        List<EmsArea> emsAreas = emsAreaDAO.getProvinceList();
        List<EmsArea> cityAreas = emsAreaDAO.getCityList();
        Map<Integer, List<EmsArea>> cityMaps = cityAreas.stream().collect(Collectors.groupingBy(c->c.getBelongto()));
        List<EmsAreaVO> resultList = Lists.newArrayList();
        for(EmsArea emsArea : emsAreas){
            List<EmsAreaVO> data = Lists.newArrayList();
            if(emsArea.getBelongto().equals(emsArea.getCityCode())){
                data.add(JacksonUtil.convertToObj(emsArea, EmsAreaVO.class));
            }else{
                if(!CollectionUtils.isEmpty(cityMaps.get(emsArea.getCityCode()))){
                    data = JacksonUtil.convertToList(cityMaps.get(emsArea.getCityCode()), EmsAreaVO.class);
                }
            }
            EmsAreaVO emsAreaVO = JacksonUtil.convertToObj(emsArea, EmsAreaVO.class);
            emsAreaVO.setCityAreaList(data);
            resultList.add(emsAreaVO);
        }
        return resultList;
    }

    private void initPriceModelOtherInfo(List<EmsPriceModelDetailVO> detailVOList){
        if(CollectionUtils.isEmpty(detailVOList)){
            return;
        }
        detailVOList.stream().forEach(d->{
            d.setPriceTypeName(PriceType.getDescFromCode(d.getPriceType()));
            d.setVoltageLevelName(VoltageLevel.getDescFromCode(d.getVoltageLevel()));
            d.setBasicElectricityName(d.getBasicElectricity() == null? null : BasicElectricity.getDescFromCode(d.getBasicElectricity()));
            d.setCalculationTypeName(IncomeCalculationType.getDescFromCode(d.getCalculationType()));
            d.setSpecialCalculationTypeName(d.getSpecialCalculationType() == null?null : IncomeCalculationType.getDescFromCode(d.getSpecialCalculationType()));
            d.setSpecialCaseName(d.getSpecialCase() == null?null : CaseType.getDescFromCode(d.getSpecialCase()));
            d.setCompareCondName(d.getCompareCond() == null?null : ConditionType.getDescFromCode(d.getCompareCond()));
        });
    }

    private String getCityName(String city,Map<Integer,EmsArea> areaMap){
        StringBuffer sb = new StringBuffer();
        new ArrayList<>(Arrays.asList(city.split(","))).stream().forEach(d->{
            sb.append(areaMap.get(Integer.parseInt(d)).getCityName() + ",");
        });
        return sb.substring(0,sb.length()-1).toString();
    }

    /**
     * 检验适用时间是否是当月时间之后,true:是
     * @param applyTime: 适用时间(格式yyyy-MM)
     */
    @SneakyThrows
    private Boolean isAfterTheCurrentMonthTime(String applyTime){
        Date parse = new SimpleDateFormat("yyyy-MM").parse(applyTime);
        if(parse.getTime() > TimeUtil.getMonthEndTime(new Date())){
            return true;
        }
        return false;
    }

    /**
     * 校验新增电价是否重复,true：重复
     * @param requestVO: 校验数据
     * @param filterPid: 需要过滤的数据的pid集合
     */
    private <T extends EmsPriceModelDetailRequestVO> boolean judgePriceModelDetailRepeat(T requestVO,List<Integer> filterPid){
        List<EmsPriceModelDetail> modelDetails = emsPriceModelDetailDAO.selectByModelId(requestVO.getModelId());
        if(CollectionUtils.isEmpty(modelDetails)){
            return false;
        }
        if(!CollectionUtils.isEmpty(filterPid)){
            modelDetails = modelDetails.stream().filter(d-> !filterPid.contains(d.getPid())).collect(toList());
        }
        //适用时间-电价类型-储能站电压组成key
        List<String> onlyKey = modelDetails.stream().map(d->d.getApplyTime() + SysConstant.COLON + d.getPriceType() + SysConstant.COLON +
                d.getVoltageLevel()).collect(toList());
        String judgeKey = requestVO.getApplyTime() + SysConstant.COLON + requestVO.getPriceType() + SysConstant.COLON + requestVO.getVoltageLevel();
        if(onlyKey.contains(judgeKey)){
            return true;
        }
        return false;
    }
}
